﻿using YNTK.Common.Helper;
using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;

namespace YNTK.Common.Core.Handler
{
    /// <summary>
    /// 请求预处理,报文解密
    /// 1.保证接口的调用的合法性
    /// 2.保证接口及数据的安全性
    /// 先保证合法，然后在合法基础上保证请求的唯一性，避免参数被篡改
    /// 先解决掉接口调用数据的安全性问题，这里采用了RSA报文加解密的方案，
    /// 保证数据安全和防止接口被恶意调用以及参数篡改的问题
    /// 解决方案：
    ///   1.参数加密：客户端和服务端参数采用RSA加密后传递，
    ///   原则上只有持有私钥的服务端才能解密客户端公钥加密的参数，避免了参数篡改的问题
    ///   2.请求签名：采用一套签名算法，对请求进行签名验证，保证请求的唯一性
    /// </summary>
    /// <seealso cref="System.Net.Http.MessageProcessingHandler"/>
    public class ArgDecryptMessageProcesssingHandler : MessageProcessingHandler
    {
        /// <summary>
        /// 处理每个发送到服务器的请求
        /// </summary>
        /// <param name="request">要处理的 HTTP 请求消息</param>
        /// <param name="cancellationToken">可由其他对象或线程用以接收取消通知的取消标记</param>
        /// <returns>已处理的 HTTP 请求消息</returns>
        protected override HttpRequestMessage ProcessRequest(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var contentType = request.Content.Headers.ContentType;

            //swagger请求直接跳过不予处理
            if (request.RequestUri.AbsolutePath.Contains("/swagger"))
            {
                return request;
            }

            //获得平台私钥
            string privarteKey = "";//私钥
            string publicKey = "";//公钥
            RSAHelper.Generator(out privarteKey, out publicKey,1024);

            //获取Get中的Query信息,解密后重置请求上下文
            if (request.Method == HttpMethod.Get)
            {
                string baseQuery = request.RequestUri.Query;
                if (!string.IsNullOrEmpty(baseQuery))
                {
                    baseQuery = baseQuery.Substring(1);
                    baseQuery = Regex.Match(baseQuery, "(sign=)*(?<sign>[\\S]+)").Groups[2].Value;
                    baseQuery = RSAHelper.RSADecrypt(privarteKey, baseQuery);
                    var requestUrl = $"{request.RequestUri.AbsoluteUri.Split('?')[0]}?{baseQuery}";
                    request.RequestUri = new Uri(requestUrl);
                }

            }

            //获取Post请求中body中的报文信息,解密后重置请求上下文
            if (request.Method == HttpMethod.Post)
            {
                string baseContent = request.Content.ReadAsStringAsync().Result;
                baseContent = Regex.Match(baseContent, "(sign=)*(?<sign>[\\S]+)").Groups[2].Value;
                baseContent = RSAHelper.RSADecrypt(privarteKey, baseContent);
                request.Content = new StringContent(baseContent);
                //此contentType必须最后设置 否则会变成默认值
                request.Content.Headers.ContentType = contentType;
            }

            return request;
        }

        /// <summary>
        /// 处理来自服务器的每个响应
        /// </summary>
        /// <param name="response">要处理的 HTTP 响应消息</param>
        /// <param name="cancellationToken">可由其他对象或线程用以接收取消通知的取消标记</param>
        /// <returns>已处理的 HTTP 响应消息</returns>
        protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
        {
            return response;
        }
    }
}
